package com.changhong.servlet;

import com.changhong.annotation.Controller;
import com.changhong.annotation.RequestMapping;
import com.changhong.annotation.Service;
import com.changhong.controller.TestController;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

/**
 * Created by Administrator on 2018/10/12
 */
public class DispatcherServlet extends HttpServlet {

    private List<String> packageNameList = new ArrayList<>();

    private Map<String, Object> instanceMap = new HashMap<>();
    private Map<String, Object> handlerMap = new HashMap<>();

    public DispatcherServlet() {
        super();
    }

    public void init(ServletConfig config) {
        scanPackage("com.changhong");

        try {
            filterAndInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        handleMap();
    }

    private void scanPackage(String packageName) {
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        String pathFile = url.getFile();
        File file = new File(pathFile);
        String fileList[] = file.list();
        for (String path : fileList) {
            File eachFile = new File(pathFile + path);
            if (eachFile.isDirectory()) {
                scanPackage(packageName + "." + eachFile.getName());
            } else {
                packageNameList.add(packageName + "." + eachFile.getName());
            }
        }
    }

    private void filterAndInstance() throws Exception {
        if (packageNameList.size() <= 0) {
            return;
        }
        for (String className : packageNameList) {
            Class<?> cName = Class.forName(className.replace(".class", "").trim());
            if (cName.isAnnotationPresent(Controller.class)) {
                Object instance = cName.newInstance();
                Controller controller = cName.getAnnotation(Controller.class);
                String key = controller.value();
                instanceMap.put(key, instance);
            } else if (cName.isAnnotationPresent(Service.class)) {
                Object instance = cName.newInstance();
                Service service = cName.getAnnotation(Service.class);
                String key = service.value();
                instanceMap.put(key, instance);
            }
        }
    }

    private void handleMap() {
        if (instanceMap.size() <= 0)
            return;

        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {
                Controller controller = entry.getValue().getClass().getAnnotation(Controller.class);
                String controllerValue = controller.value();
                Method[] methods = entry.getValue().getClass().getMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        String requestMappingValue = requestMapping.value();
                        handlerMap.put("/" + controllerValue + requestMappingValue, method);
                    }
                }
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String url = req.getRequestURI();
        String context = req.getContextPath();
        String path = url.replace(context, "");

        if(!this.handlerMap.containsKey(path)){
            resp.getWriter().write("404 NOT FOUND!");
            return;
        }

        Method method = (Method) handlerMap.get(path);


        //获取方法的参数列表
        Class<?>[] parameterTypes = method.getParameterTypes();

        //获取请求的参数
        Map<String, String[]> parameterMap = req.getParameterMap();

        //保存参数值
        Object [] paramValues= new Object[parameterTypes.length];

        //方法的参数列表
        for (int i = 0; i < parameterTypes.length; i++){
            //根据参数名称，做某些处理
            String requestParam = parameterTypes[i].getSimpleName();

            if (requestParam.equals("HttpServletRequest")){
                //参数类型已明确，这边强转类型
                paramValues[i]=req;
                continue;
            }
            if (requestParam.equals("HttpServletResponse")){
                paramValues[i]=resp;
                continue;
            }
            if(requestParam.equals("String")){
                for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
                    String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
                    paramValues[i]=value;
                }
            }
        }

        try {
            TestController testController = (TestController) this.instanceMap.get("testController");
            method.invoke(testController, paramValues);//obj是method所对应的实例 在ioc容器中
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
